/**
 * UTF8 to UCS4 conversion facilities.
 *
 * Contains slightly modified code of LibParserUtils
 * Original and this code is licensed under the MIT License,
 * http://www.opensource.org/licenses/mit-license.php
 * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
 *
 * A. Shabanov, 2009
 */

#pragma once

#include <stddef.h>
#include <stdint.h>

#define UTF_STATUS_OK               (0)
#define UTF_STATUS_ERR_BADPARM      (-1)
#define UTF_STATUS_ERR_NEEDDATA     (-2)
#define UTF_STATUS_ERR_INVALID      (-2)
#define UTF_STATUS_ERR_NOMEM        (-3)


/**
 * UNSAFE: converts utf8 sequence to ucs4 sequence without length checks
 * \return pointer to the end of ucs4 string, NULL otherwise
 */
uint32_t * utf8_to_ucs4_nocheck(uint8_t * utf8, uint8_t * utf8end, uint32_t * ucs4);

void ucs4_tolower(uint32_t * ucs4, uint32_t * ucs4_end);

/**
 * Convert a UTF-8 multibyte sequence into a single UCS-4 character
 *
 * Encoding of UCS values outside the UTF-16 plane has been removed from
 * RFC3629. This function conforms to RFC2279, however.
 *
 * \param s     The sequence to process
 * \param len   Length of sequence
 * \param ucs4  Pointer to location to receive UCS-4 character (host endian)
 * \param clen  Pointer to location to receive byte length of UTF-8 sequence
 * \return UTF_STATUS_OK on success, appropriate error UTF_STATUS_ERR_x otherwise
 */
int utf8_to_ucs4(const uint8_t *s, size_t len, uint32_t *ucs4, size_t *clen);

/**
 * Convert a single UCS-4 character into a UTF-8 multibyte sequence
 *
 * Encoding of UCS values outside the UTF-16 plane has been removed from
 * RFC3629. This function conforms to RFC2279, however.
 *
 * \param ucs4  The character to process (0 <= c <= 0x7FFFFFFF) (host endian)
 * \param s     Pointer to pointer to output buffer, updated on exit
 * \param len   Pointer to length, in bytes, of output buffer, updated on exit
 * \return PARSERUTILS_OK on success, appropriate error otherwise
 */
int utf8_from_ucs4(uint32_t ucs4, uint8_t **s, size_t *len);

/**
 * Calculate the length (in characters) of a bounded UTF-8 string
 *
 * \param s    The string
 * \param max  Maximum length
 * \param len  Pointer to location to receive length of string
 * \return UTF_STATUS_OK on success, appropriate error otherwise
 */
int utf8_length(const uint8_t *s, size_t max, size_t *len);

/**
 * Calculate the length (in bytes) of a UTF-8 character
 *
 * \param s    Pointer to start of character
 * \param len  Pointer to location to receive length
 * \return UTF_STATUS_OK on success, appropriate error otherwise
 */
int utf8_char_byte_length(const uint8_t *s, size_t *len);

/**
 * Find previous legal UTF-8 char in string
 *
 * \param s        The string
 * \param off      Offset in the string to start at
 * \param prevoff  Pointer to location to receive offset of first byte of
 *                 previous legal character
 * \return UTF_STATUS_OK on success, appropriate error otherwise
 */
int utf8_prev(const uint8_t *s, uint32_t off, uint32_t *prevoff);

/**
 * Find next legal UTF-8 char in string
 *
 * \param s        The string (assumed valid)
 * \param len      Maximum offset in string
 * \param off      Offset in the string to start at
 * \param nextoff  Pointer to location to receive offset of first byte of
 *                 next legal character
 * \return UTF_STATUS_OK on success, appropriate error otherwise
 */
int utf8_next(const uint8_t *s, uint32_t len, uint32_t off, uint32_t *nextoff);

/**
 * Find next legal UTF-8 char in string
 *
 * \param s        The string (assumed to be of dubious validity)
 * \param len      Maximum offset in string
 * \param off      Offset in the string to start at
 * \param nextoff  Pointer to location to receive offset of first byte of
 *                 next legal character
 * \return UTF_STATUS_OK on success, appropriate error otherwise
 */
int utf8_next_paranoid(const uint8_t *s, uint32_t len, uint32_t off, uint32_t *nextoff);

